package com.novel.disk.framework.exception.handler;

import com.novel.disk.common.DateUtils;
import com.novel.disk.common.Result;
import com.novel.disk.framework.exception.BusinessException;
import com.novel.disk.framework.exception.LoginTimeoutException;
import com.novel.disk.framework.exception.base.SuperException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.github.junrar.exception.UnsupportedRarV5Exception;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.connector.ClientAbortException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.ResourceAccessException;

import java.io.FileNotFoundException;
import java.text.ParseException;
import java.util.List;

/**
 * 异常处理<br/>
 * 异常状态码根据前端业务，暂不做修改
 *
 * @author novel
 * @date 2018/7/28
 */
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    /**
     * 用户登录超时异常
     *
     * @param e 用户登录超时异常
     * @return
     */
    @ExceptionHandler(value = LoginTimeoutException.class)
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    public Result handleLoginTimeoutException(LoginTimeoutException e) {
        log.error("用户登录超时异常，{},{},{}", DateUtils.formatLog(), e.getCode(), e.getMessage());
        return getResult(e);
    }


    /**
     * 业务异常
     *
     * @param e 业务异常
     * @return
     */
    @ExceptionHandler(value = BusinessException.class)
    @ResponseStatus(HttpStatus.OK)
    public Result handleBusinessException(BusinessException e) {
        log.error("业务异常，{},{},{}", DateUtils.formatLog(), e.getCode(), e.getMessage());
        return getResult(e);
    }

    @ExceptionHandler(value = BindException.class)
    @ResponseStatus(HttpStatus.OK)
    public Result handleBindException(BindException e) {
        log.error("参数异常，{},{},{}", DateUtils.formatLog(), 200, e.getMessage());
        return getResult(e);
    }

    @ExceptionHandler(value = HttpClientErrorException.class)
    @ResponseStatus(HttpStatus.OK)
    public Result httpClientErrorException(HttpClientErrorException e) {
        log.error("请求异常，{},{},{}", DateUtils.formatLog(), 200, e.getMessage());
        Result resultView = new Result();
        resultView.setResult(false);
        if (e.getMessage() != null && e.getMessage().contains("对不起,您无权限进行操作")) {
            resultView.setMsg("对不起,您无权限进行操作");
            resultView.setCode(401);
        } else {
            resultView.setMsg(e.getMessage());
            resultView.setCode(500);
        }
        return resultView;
    }

    @ExceptionHandler(value = Exception.class)
    public Result handle(Exception e) {
        if (e instanceof DuplicateKeyException) {
            log.error("{},{},{}", DateUtils.formatLog(), "106", "数据主键重复" + e.getMessage());
            Result resultView = new Result();
            resultView.setResult(false);
            resultView.setCode(500);
            resultView.setMsg("数据主键重复");
            return resultView;
        } else if (e instanceof ClientAbortException) {
            log.error("{},{},{}", DateUtils.formatLog(), "500", "远程主机强迫关闭了一个现有的连接" + e.getMessage());
            return null;
        } else if (e instanceof ParseException) {
            log.error("{},{},{}", DateUtils.formatLog(), "400", "时间格式不正确" + e.getMessage());
            Result resultView = new Result();
            resultView.setResult(false);
            resultView.setCode(500);
            resultView.setMsg("时间格式不正确");
            return resultView;
        } else if (e instanceof JsonProcessingException) {
            log.error("{},{},{}", DateUtils.formatLog(), "400", "JSON数据处理异常" + e.getMessage());
            Result resultView = new Result();
            resultView.setResult(false);
            resultView.setCode(500);
            resultView.setMsg("JSON数据处理异常");
            return resultView;
        } else if (e instanceof HttpRequestMethodNotSupportedException) {
            log.error("{},{},{}", DateUtils.formatLog(), "400", "请求方式不正确！" + e.getMessage());
            Result resultView = new Result();
            resultView.setResult(false);
            resultView.setCode(500);
            resultView.setMsg("请求方式不正确！");
            return resultView;
        } else if (e instanceof ResourceAccessException) {
            log.error("{},{},{}", DateUtils.formatLog(), "400", "服务器异常！" + e.getMessage());
            Result resultView = new Result();
            resultView.setResult(false);
            resultView.setCode(500);
            resultView.setMsg("服务器异常！");
            return resultView;
        } else if (e instanceof FileNotFoundException) {
            log.error("{},{},{}", DateUtils.formatLog(), "400", "文件不存在！" + e.getMessage());
            Result resultView = new Result();
            resultView.setResult(false);
            resultView.setCode(500);
            resultView.setMsg("文件不存在！");
            return resultView;
        } else if (e instanceof UnsupportedRarV5Exception) {
            log.error("{},{},{}", DateUtils.formatLog(), "400", "文件解压失败！" + e.getMessage());
            Result resultView = new Result();
            resultView.setResult(false);
            resultView.setCode(500);
            resultView.setMsg("文件不支持解压！");
            return resultView;
        } else {
            log.error("{},{},{}", DateUtils.formatLog(), "-1", "未知错误" + e.getMessage());
            Result resultView = new Result();
            resultView.setResult(false);
            resultView.setCode(500);
            resultView.setMsg("未知错误");
            e.printStackTrace();
            return resultView;
        }
    }

    /**
     * 设置异常信息
     *
     * @param e
     * @return
     */
    private Result getResult(SuperException e) {
        Result result = new Result();
        result.setMsg(e.getMessage());
        result.setResult(false);
        result.setCode(e.getCode());
        return result;
    }

    /**
     * 参数异常
     *
     * @param e
     * @return
     */
    private Result getResult(BindException e) {
        BindingResult bindingResult = e.getBindingResult();
        List<ObjectError> allErrors = bindingResult.getAllErrors();
        Result result = new Result();
        result.setMsg("");
        allErrors.forEach(item -> {
            result.setMsg(result.getMsg() + " " + item.getDefaultMessage());
        });
        result.setResult(false);
        result.setCode(200);
        return result;
    }
}
